﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AAA.Recognition
{
    public class DigitalRecognition
    {
        private Sensor[] _sensors;
        private List<DigitalSample> _lstTrainingSet;

        private int _iHSensorCnt;
        private int _iVSensorCnt;
        private double _dThreshold;

        public double Threshold
        {
            get { return _dThreshold; }
            set { _dThreshold = value; }
        }

        public DigitalRecognition(int iHSensorCnt, int iVSensorCnt)
        {
            _iHSensorCnt = iHSensorCnt;
            _iVSensorCnt = iVSensorCnt;


            _lstTrainingSet = new List<DigitalSample>();
        }

        private Sensor CrossCount(int iX, int iY, int iWidth, int iHeight, double[] dInputs)
        {
            Sensor sensor = new Sensor();
            bool isHit = false;
            int iHitCount;
            int iTotalHitCount;

            iHitCount = 0;
            iTotalHitCount = 0;
            for (int i = 0; i < iY; i++)
            {
                isHit = (dInputs[i * iWidth + iX] < Threshold) ? true : false;

                if (!isHit)
                {
                    if (iHitCount > 0)
                        iTotalHitCount++;
                    iHitCount = 0;
                }
                else
                    iHitCount++;
            }
            sensor.UpCrossCount = iTotalHitCount;

            iHitCount = 0;
            iTotalHitCount = 0;
            for (int i = iY; i < iHeight; i++)
            {
                isHit = (dInputs[i * iWidth + iX] < Threshold) ? true : false;

                if (!isHit)
                {
                    if (iHitCount > 0)
                        iTotalHitCount++;
                    iHitCount = 0;
                }
                else
                    iHitCount++;
            }
            sensor.DownCrossCount = iTotalHitCount;

            iHitCount = 0;
            iTotalHitCount = 0;
            for (int i = 0; i < iX; i++)
            {
                isHit = (dInputs[iY * iWidth + i] < Threshold) ? true : false;

                if (!isHit)
                {
                    if (iHitCount > 0)
                        iTotalHitCount++;
                    iHitCount = 0;
                }
                else
                    iHitCount++;
            }
            sensor.LeftCrossCount = iTotalHitCount;

            iHitCount = 0;
            iTotalHitCount = 0;
            for (int i = iX; i < iWidth; i++)
            {
                isHit = (dInputs[iY * iWidth + i] < Threshold) ? true : false;

                if (!isHit)
                {
                    if (iHitCount > 0)
                        iTotalHitCount++;
                    iHitCount = 0;
                }
                else
                    iHitCount++;
            }
            sensor.RightCrossCount = iTotalHitCount;

            return sensor;
        }

        public int Recognize(int iWidth, int iHeight, double[] dInputs)
        {
            double dXInterval = (double)iWidth / (double)_iHSensorCnt;
            double dYInterval = (double)iHeight / (double)_iVSensorCnt;
            int iX;
            int iY;
            DigitalSample digitalSample = new DigitalSample(_iHSensorCnt, _iVSensorCnt);
            DigitalSample resultSample = null;
            double dMatchRate;
            double dMaxMatchRate = -1;

            digitalSample = Calculate(iWidth, iHeight, dInputs);

            for(int i = 0; i < _lstTrainingSet.Count; i++)
            {
                dMatchRate = (_lstTrainingSet[i].MatchCount(digitalSample.Sensors) / (double)(_iHSensorCnt * _iVSensorCnt));
                if (dMatchRate > dMaxMatchRate)
                {
                    dMaxMatchRate = dMatchRate;
                    resultSample = _lstTrainingSet[i];
                }
            }
            return resultSample.Value;
        }

        private DigitalSample Calculate(int iWidth, int iHeight, double[] dInputs)
        {
            DigitalSample sample = new DigitalSample(_iHSensorCnt, _iHSensorCnt);
            double dXInterval = (double)iWidth / (double)_iHSensorCnt;
            double dYInterval = (double)iHeight / (double)_iVSensorCnt;
            int iX;
            int iY;

            for (int y = 0; y < _iVSensorCnt; y++)
                for (int x = 0; x < _iHSensorCnt; x++)
                {
                    iX = (int)(dXInterval / 2 + x * dXInterval);
                    iY = (int)(dYInterval / 2 + y * dYInterval);

                    sample.SetSensor(x, y, CrossCount(iX, iY, iWidth, iHeight, dInputs));
                }
            return sample;
        }

        public void Training(int iWidth, int iHeight, double[] dInputs, int iResult)
        {
            DigitalSample sample = Calculate(iWidth, iHeight, dInputs);
            sample.Value = iResult;
            _lstTrainingSet.Add(sample);
        }

    }
}
